package nio.selector;

import nio.NioUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * Server
 *
 * @author chenxin
 * @date 2022/05/24 18:27
 **/
public class Server {

    public static void main(String[] args) throws IOException {
        // 1. 创建selector 管理多个channel
        Selector selector = Selector.open();

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);

        // 2. 建立联系 channel注册到selector
        SelectionKey register = serverSocketChannel.register(selector, 0, null);
        // 设置关注请求事件
        register.interestOps(SelectionKey.OP_ACCEPT);

        serverSocketChannel.bind(new InetSocketAddress(8080));
        while (true) {
            // 3. select 方法 没有事件发生时 线程阻塞
            selector.select();

            // 4. 处理事件 selectionKeys内部包含了所有发生的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                System.out.println("key: " + key);
                // 处理这个key之后 需要从selectedKeys集合中删除
                iterator.remove();

                SelectableChannel channel = key.channel();

                // 连接事件
                if (key.isAcceptable()) {
                    ServerSocketChannel acceptChannel = (ServerSocketChannel) channel;

                    SocketChannel sc = acceptChannel.accept();
                    System.out.println(sc);

                    // 将新拿到的连接注册到selector 并设为非阻塞模式
                    sc.configureBlocking(false);
                    sc.register(selector, SelectionKey.OP_READ, null);
                }
                // 读取事件
                else if (key.isReadable()) {
                    try {
                        SocketChannel readChannel = (SocketChannel) channel;
                        ByteBuffer byteBuffer = ByteBuffer.allocate(16);
                        int read = readChannel.read(byteBuffer);
                        if (read == -1) {
                            // 服务器已正常断开
                            key.cancel();
                            continue;
                        }

                        byteBuffer.flip();
                        System.out.println(Charset.defaultCharset().decode(byteBuffer));
                    } catch (Exception e) {
                        e.printStackTrace();
                        key.cancel();
                    }
                }
            }

        }
    }

}